#pragma once


#include <string>
#include <stdint.h>



/**
 * \brief  Callback functions to implement behaviors of different platforms.
 *
 * If a function is marked as "may not be necessary", you can just ignore it.
 * If a function is marked as "is not necessary", you should ignore it.
 * If a function is marked as "should be empty", you should implement it and do nothing in it.
 */
typedef struct {

    // System Interface

    /**
     * \brief                     Get system writable path, e.g. "/tmp/".
     * The function should be empty when isPhotoUseMemorySpace is set to true,
     * and GetSystemFriendlyName() returns fixed name.
     *
     * \param p_systemDataPrefix  Pointer to destination buffer.
     * \return                    void.
     */
    void (*GetSystemDataPrefix)(char *p_systemDataPrefix);

    /**
     * \brief                     Generate MAC address and device name.
     * The function should be empty when GetSystemFriendlyName() return fixed name.
     *
     * \param p_systemDataPrefix  Pointer to buffer containing system writable path.
     * \return                    void.
     */
    void (*GenerateSystemInfo)(const char *p_systemDataPrefix);

    /**
     * \brief         Get real raw MAC address.
     * \param rawMac  Pointer to external output buffer where raw MAC address will be stored into.
     * \return        void.
     */
    void (*GetMacAddressRaw)(char rawMac[6]);

    /**
     * \brief   Get the name showed on Apple device.
     * \return  String containing the name showed on Apple device.
     */
    std::string (*GetSystemFriendlyName)();

    /**
     * \brief   Backup original system volume value.
     * The function may not be necessary.
     *
     * \return  void.
     */
    void (*BackupVolume)(const std::string& ip);

    /**
     * \brief   Restore system volume to original value.
     * The function may not be necessary.
     *
     * \return  void.
     */
    void (*RestoreVolume)(const std::string& ip);

    /**
     * \brief                Set system volume to given value.
     * The function may not be necessary.
     *
     * \param volumePercent  Percertage of maximum volume value, e.g. 0.3 == 30%.
     * \return               void.
     */
    void (*SetVolume)(const std::string& ip, float volumePercent);



    // Playback Utils

    /**
     * \brief   Enter playback environment of AirPlay receiver.
     * The function may not be necessary.
     *
     * \return  void.
     */
    void (*EnterAirFlyEnv)(const std::string& ip);

    /**
     * \brief   Quit playback environment of AirPlay receiver.
     * The function may not be necessary.
     *
     * \return  void.
     */
    void (*QuitAirFlyEnv)(const std::string& ip);



    // Video Interface

    /**
     * \brief   Get video player status.
     * \return  Is video player started.
     */
    bool (*IsVideoPlaybackStarted)(const std::string& ip);

    /**
     * \brief   Get video player status.
     * \return  Is video player paused.
     */
    bool (*IsVideoPlaybackPaused)(const std::string& ip);

    /**
     * \brief                Start video playback.
     * \param path           Pointer to buffer containing http URL.
     * \param startPosition  Percertage of starting position, e.g. 0.3 == 30%.
     * \return               void
     */
    void (*StartVideoPlayback)(const std::string& ip, char *path, float startPosition);

    /**
     * \brief   Stop video playback.
     * \return  void
     */
    void (*StopVideoPlayback)(const std::string& ip);

    /**
     * \brief   Pause video playback.
     * \return  void
     */
    void (*PauseVideoPlayback)(const std::string& ip);

    /**
     * \brief   Resume video playback.
     * \return  void
     */
    void (*ResumeVideoPlayback)(const std::string& ip);

    /**
     * \brief           Seek video playback to a new position.
     * \param position  The new playback position.
     * \return          void
     */
    void (*SeekVideoBySec)(const std::string& ip, int64_t position);

    /**
     * \brief   Get video playback position.
     * \return  Current playback position. (unit: second)
     */
    double (*GetVideoPositionSec)(const std::string& ip);

    /**
     * \brief   Get video duration.
     * \return  The video duration. (unit: second)
     */
    double (*GetVideoDurationSec)(const std::string& ip);

    /**
     * \brief   Get video playback cached position.
     * The function may not be necessary.
     *
     * \return  Current playback cached position. (unit: second)
     */
    double (*GetVideoCachePositionSec)(const std::string& ip);



    // Audio Interface

    /**
     * \brief   Get audio player status.
     * \return  Is audio player started.
     */
    bool (*IsAudioPlaybackStarted)(const std::string& ip);

    /**
     * \brief   Get audio player status.
     * \return  Is audio player paused.
     */
    bool (*IsAudioPlaybackPaused)(const std::string& ip);

    /**
     * \brief             Start audio playback.
     * \param bits        The audio bitdepth.
     * \param channels    The audio channels.
     * \param sampleRate  The audio samplerate.
     * \return            void
     */
    void (*StartAudioPlayback)(const std::string& ip, int bits, int channels, int sampleRate);

    /**
     * \brief   Stop audio playback.
     * \return  void
     */
    void (*StopAudioPlayback)(const std::string& ip);

    /**
     * \brief   Hide audio playback UI.
     * The function may not be necessary.
     *
     * \return  void
     */
    void (*HideAudioPlayback)(const std::string& ip);

    /**
     * \brief   Show audio playback UI.
     * The function may not be necessary.
     *
     * \return  void
     */
    void (*ShowAudioPlayback)(const std::string& ip);

    /**
     * \brief   Pause audio playback.
     * \return  void
     */
    void (*PauseAudioPlayback)(const std::string& ip);

    /**
     * \brief   Resume audio playback.
     * \return  void
     */
    void (*ResumeAudioPlayback)(const std::string& ip);

    /**
     * \brief   Flush the audio pipe buffer after start, pause and stop.
     * The function may not be necessary.
     *
     * \return  void
     */
    void (*FlushAudioBuffer)(const std::string& ip);

    /**
     * \brief        Write audio PCM frame to player.
     * \param p_src  Pointer to source buffer.
     * \param size   PCM frame size. (unit: byte)
     * \return       Copied size. (unit: byte)
     */
    int (*WriteAudioData)(const std::string& ip, const void *p_src, int size);

    /**
     * \brief         Refresh audio ID3 information on UI.
     * The function may not be necessary.
     *
     * \param album   The audio album.
     * \param title   The audio title.
     * \param artist  The audio artist.
     * \return        void
     */
    void (*RefreshTrackInfo)(const std::string& ip, const std::string& album, const std::string& title, const std::string& artist);

    /**
     * \brief                Refresh audio cover artwork on UI.
     * The function may not be necessary.
     * The function is not necessary when isPhotoUseMemorySpace is set to true.
     *
     * \param coverFilePath  Pointer to buffer containing cover artwork file path.
     * \return               void
     */
    void (*RefreshCoverArtFromFile)(const std::string& ip, char *coverFilePath);

    /**
     * \brief        Refresh audio cover artwork on UI.
     * The function may not be necessary.
     * The function is not necessary when isPhotoUseMemorySpace is set to false.
     *
     * \param p_src  Pointer to source buffer.
     * \param size   Cover artwork data size. (unit: byte)
     * \return       void
     */
    void (*RefreshCoverArtFromBuffer)(const std::string& ip, const void *p_src, int size);

    /**
     * \brief             Refresh audio playback progress on UI.
     * The function may not be necessary.
     *
     * \param durationMS  The audio duration. (unit: millisecond)
     * \param positionMS  Current audio playback position. (unit: millisecond)
     * \return            void
     */
    void (*RefreshProgress)(const std::string& ip, unsigned durationMS, unsigned positionMS);



    // Photo Interface

    /**
     * \brief               Start photo(JPEG or PNG format) playback.
     * The function is not necessary when isPhotoUseMemorySpace is set to true.
     *
     * \param filePath      String containing photo file URL.
     * \param isFirstPhoto  Is this phto the first one.
     * \return              void
     */
    void (*StartPhotoPlaybackFromFile)(const std::string& ip, const std::string& filePath, bool isFirstPhoto);

    /**
     * \brief               Start photo(JPEG or PNG format) playback.
     * The function is not necessary when isPhotoUseMemorySpace is set to false.
     *
     * \param p_src         Pointer to source buffer.
     * \param size          Photo data size. (unit: byte)
     * \param isFirstPhoto  Is this phto the first one.
     * \return              void
     */
    void (*StartPhotoPlaybackFromBuffer)(const std::string& ip, const void *p_src, int size, bool isFirstPhoto);

    /**
     * \brief   Stop photo playback.
     * \return  void
     */
    void (*StopPhotoPlayback)(const std::string& ip);



    // Mirror Interface

    /**
     * \brief             Provide mirror audio parameters.
     * \param bits        The mirror audio bitdepth.
     * \param channels    The mirror audio channels.
     * \param sampleRate  The mirror audio samplerate.
     * \return            void
     */
    void (*PreprocessMirrorParameters)(const std::string& ip, int bits, int channels, int sampleRate);

    /**
     * \brief              Start mirror playback.
     * \param isAudioOnly  Is audio data only.
     * \return             void
     */
    void (*StartMirrorPlayback)(const std::string& ip, bool isAudioOnly);

    /**
     * \brief   Stop mirror playback.
     * \return  void
     */
    void (*StopMirrorPlayback)(const std::string& ip);

    /**
     * \brief        Rotate mirror video screen.
     * \param angle  The clockwise rotation angle.
     * \return       void
     */
    void (*RotateMirrorVideo)(const std::string& ip, int angle);

    /**
     * \brief           Write mirror audio PCM frame to player.
     * \param p_src     Pointer to source buffer.
     * \param size      PCM frame size. (unit: byte)
     * \param ptsValue  PTS value.
     * \return          Copied size. (unit: byte)
     */
    int (*WriteMirrorAudioData)(const std::string& ip, const void *p_src, int size, double ptsValue);

    /**
     * \brief           Write mirror video H.264 frame to player.
     * \param p_src     Pointer to source buffer.
     * \param size      H.264 frame size. (unit: byte)
     * \param ptsValue  PTS value.
     * \return          Copied size. (unit: byte)
     */
    int (*WriteMirrorVideoData)(const std::string& ip, const void *p_src, int size, double ptsValue);

} AirFlyFunctionCbs_t;



/**
 * \brief  The parameters to start AirFly Receiver.
 */
typedef struct {
    /// The password string. Set empty to disable AirPlay Password Protection.
    char password[256];

    /// Use memory space or flash space to store photos.
    /// Set true to use memory space.\n
    /// If using memory space, system may crash when no enough memory.
    bool isPhotoUseMemorySpace;

    /// The resolution string.
    /// "720" : 1280 x  720,  720p Standard.
    /// "1080": 1920 x 1080, 1080p Standard.
    /// "1440": 2560 x 1440,  720p Retina.
    /// "2160": 3840 x 2160, 1080p Retina.
    /// Empty : 1280 x  720,  720p Standard.
    char preferResolution[256];

    /// The player level.
    bool isModernPlayer;

    /// Callback functions to implement behaviors of different platforms.
    AirFlyFunctionCbs_t cbs;

} AirFlyParameters_t;



/**
 * \brief        Use parameters to init AirFly Receiver.
 * \param paras  Some parameters.
 * \return       void
 */
void AirFlyInit(AirFlyParameters_t paras);

/**
 * \brief   Start AirFly Receiver.
 * \return  void
 */
void AirFlyStartAll();

/**
 * \brief   Stop AirFly Receiver.
 * \return  void
 */
void AirFlyStopAll();

/**
 * \brief   Start AirFly Receiver, without starting mDNS client.
 * \return  void
 */
void AirFlyStartServer();

/**
 * \brief   Stop AirFly Receiver, without stopping mDNS client.
 * \return  void
 */
void AirFlyStopServer();

/**
 * \brief   Re-publish AirFly Receiver Services.
 * \return  void
 */
void AirFlyRePublish();

/**
 * \brief           Set password of AirPlay Password Protection.
 * If the password is different from the old password, AirFly Receiver will restart.
 *
 * \param password  Pointer to buffer containing password.
 * \return          void
 */
void AirFlySetPassword(const char *password);

/**
 * \brief     Disconnect the connection between a device and AirFly Receiver.
 *
 * \param ip  Pointer to buffer containing the device IPv4 address.
 * \return    void
 */
void AirFlyKickoutDevice(const char *ip);



/**
 * An example:
 *
 *     #include "AirFly.h"
 *     #include <string>
 *     #include <unistd.h>
 *
 *     static std::string GetSystemFriendlyName()
 *     {
 *         return "AirFly Demo";
 *     }
 *
 *     int main()
 *     {
 *         AirFlyParameters_t paras;
 *         strcpy(paras.password, "");
 *         paras.isPhotoUseMemorySpace = false;
 *         strcpy(paras.preferResolution, "");
 *         paras.isModernPlayer = true;
 *         memset(&paras.cbs, 0, sizeof(AirFlyFunctionCbs_t));  // important
 *
 *         paras.cbs.GetSystemFriendlyName = GetSystemFriendlyName;
 *
 *         AirFlyInit(paras);
 *         AirFlyStartAll();
 *
 *         pause();
 *         return 0;
 *     }
 */
